#include "memory.h"

#define DIV_ROUND_UP(n, x) (((n) + (x) - 1) / (x))
#define PG_SIZE 4096

e820_memmap_t ards[10];
uint8_t frame_bitmap[32768]; // 32768 * 8 * 4096 = 1073741824 = 1GiB
extern uint32_t end; // 定义于linker.ld，内核结束位置
uint32_t kernel_end = (uint32_t) &end;

int get_bit(uint8_t *btmp, int n)
{
    int byte = n / 8, remain = n % 8;
    return (btmp[byte] & (1 << remain)) >> remain;
}

void set_bit(uint8_t *btmp, int n, bool value)
{
    int byte = n / 8, remain = n % 8;
    if (value) btmp[byte] |= 1 << remain;
    else btmp[byte] &= ~(1 << remain);
}

int alloc_bit(uint8_t *btmp, int btmp_size)
{
    // 寻找第一个空闲位
    for (int i = 0; i < btmp_size; i++) {
        if (btmp[i] == 0) continue;
        for (int j = 0; j < 8; j++) {
            if ((btmp[i] & (1 << j))) return i * 8 + j;
        }
    }
    return -1;
}

void init_memory(int ard_count, e820_memmap_t *ard_buf)
{
    memcpy(ards, ard_buf, ard_count * sizeof(e820_memmap_t));
    for (int i = 0; i < ard_count; i++) {
        e820_memmap_t ard = ards[i];
        if (ard.type == 1 && ard.base_low >= 0x100000) { // 1MiB以前的均认为不可用
            int start = DIV_ROUND_UP(ard.base_low, PG_SIZE), end = DIV_ROUND_UP(ard.base_low + ard.length_low, PG_SIZE);
            for (int i = start; i <= end; i++) set_bit(frame_bitmap, i, true); // 我们认为 1 代表可用而 0 代表不可用
        }
    }
    // 0x100000 - kernel_end 为 kernel.bin，显然不可用
    int kernel_start_frame = DIV_ROUND_UP(0x100000, PG_SIZE), kernel_end_frame = DIV_ROUND_UP(kernel_end, PG_SIZE);
    for (int i = kernel_start_frame; i <= kernel_end_frame; i++) set_bit(frame_bitmap, i, false);
    // 0x400000 = 4MiB，显然可用，其对应到第多少位呢？0x400000 / 0x1000 = 0x400，也就是第1024位
}

int phys_alloc()
{
    int bit = alloc_bit(frame_bitmap, 32768);
    set_bit(frame_bitmap, bit, false);
    int addr = bit * PG_SIZE;
    memset((char *) addr, 0, PG_SIZE - 1);
    return addr;
}

void phys_free(int mem)
{
    set_bit(frame_bitmap, mem / PG_SIZE, true);
}